//
//  String.swift
//  CooperSwift
//
//  Created by 计海峰 on 2020/3/5.
//  Copyright © 2020 CooperSwift. All rights reserved.
//

public extension String {
    
    /// 统计字数
    func countStr(_ str: String) -> Int {
        let tok =  self.components(separatedBy: str)
        return tok.count - 1
    }
    
    /// 字符串转 Base64
    func base64() -> String? {
        guard let plainData =  self.data(using: .utf8) else {
            return nil
        }
        return  plainData.base64EncodedString()
    }

    /// 拷贝多个
    func repeatString(_ times: Int ) -> String {
        var result = String()
        for _ in 0...times {
            result += self
        }
        return result
    }
    
    /// 整体反转字符串
    func reverse() -> String {
        return String(self.reversed())
    }
    
    /// 去掉特殊字符串 默认去掉空
    func clearText(_ targetText: String = " ") -> String {
        return self.replacingOccurrences(of: targetText, with: "")
    }
    
    /// 从某个位置开始截取：
    /// - Parameter index: 起始位置
    func substring(from index: Int) -> String {
        if(self.count > index){
            let startIndex = self.index(self.startIndex, offsetBy: index)
            let subString = self[startIndex..<self.endIndex];
            return String(subString);
        }else{
            return ""
        }
    }
    
    /// 从零开始截取到某个位置：
    /// - Parameter index: 达到某个位置
    func substring(to index: Int) -> String {
        if(self.count > index){
            let endindex = self.index(self.startIndex, offsetBy: index)
            let subString = self[self.startIndex..<endindex]
            return String(subString)
        }else{
            return self
        }
    }
    
    /// 某个范围内截取
    /// - Parameter rangs: 范围
    func subString(rang rangs:NSRange) -> String{
        var string = String()
        if(rangs.location >= 0) && (self.count > (rangs.location + rangs.length)){
            let startIndex = self.index(self.startIndex, offsetBy: rangs.location)
            let endIndex = self.index(self.startIndex,offsetBy: (rangs.location + rangs.length))
            let subString = self[startIndex..<endIndex]
            string = String(subString)
        }
        return string
    }
    
    /// 一些转换
    func toDouble() -> Double? {
        return Double(self)
    }
    
    func toFloat() -> Float? {
        return Float(self)
    }
    
    func toInt() -> Int? {
        return Int(self)
    }
    
    func toURL() -> NSURL? {
        return NSURL(string: self)
    }
    
    /// 转为日期
    /// - Returns: 日期
    func toDate(_ dateFormat: String? = nil) -> Date? {
      let dateFormatter = DateFormatter()
        dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
        if let dateFormat = dateFormat {
            dateFormatter.dateFormat = dateFormat
        }else {
            if self.count == 19 {
              dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
            }else if self.count == 10 {
              dateFormatter.dateFormat = "yyyy-MM-dd"
            }else {
                return nil
            }
        }
      let date = dateFormatter.date(from: self)
      return date
    }
    
    /// 拼接地址和参数
    /// - Parameters:
    ///   - url: 基本地址
    ///   - params: 参数
    func spellUrlAndParams(params: [String : Any]) -> String? {
        let paramsStr = params.map { (key: String, value: Any) -> String in
            return "\(key)=\(value)"
        }.joined(separator: "&")
        return "\(self)?\(paramsStr)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
    }

    
    ///获取文字的宽度
    func getStringWidth(_ font: UIFont) -> CGFloat {
        let textSize = self.size(withAttributes: [NSAttributedString.Key.font: font])
        return textSize.width
    }

    ///获取文字的高度(需要一个最大宽度)
    func getStringHeight(font: UIFont, maxWidth: CGFloat) -> CGFloat {
        let rect = self.boundingRect(with: CGSize.init(width: maxWidth, height: CGFloat(MAXFLOAT)), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
        return rect.height
    }
    
    func print() -> Void {
        Swift.debugPrint(self)
    }
    
}

// MARK: - 限制输入
// 正则
// https://c.runoob.com/front-end/854/
public enum RegexRuleEnum {
    
    // 字符串
    case pureNum /// 纯数字
    case chinese /// 中文 ^[\u4e00-\u9fa5]{0,}$
    case letter /// 只能输入由26个英文字母组成的字符串
    
    // 金额
    case moneyNoPoint ///  有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000"：^[1-9][0-9]*$
    case moneyNoPointNoZeroStart /// 这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式：^(0|[1-9][0-9]*)$
    
    case moneyPointNoEnd ///  小数点后面至少应该有1位数 ,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的  ^[0-9]+(.[0-9]+)?$
    case moneyPointCanEnd
    case moneyStandard ///  小数点后面必须有两位    ^[0-9]+(.[0-9]{1,2})?$
    
    // 特殊
    case phone /// 手机号
    case url /// 地址 [a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
    case email /// 邮箱 ^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
    case idCard /// 身份证号(15位、18位数字)，最后一位是校验位，可能为数字或字符X：(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)
    
    // 密码
    case password /// 密码(以字母开头，长度在6~18之间，只能包含字母、数字和下划线) ^[a-zA-Z]\w{5,17}$
    case passwordStrong /// 强密码(必须包含大小写字母和数字的组合，可以使用特殊字符，长度在8-10之间)  ^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
    case passwordStrongNoSpecial /// 强密码(必须包含大小写字母和数字的组合，不能使用特殊字符，长度在 8-10 之间)  ^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$
    
    // 昵称
    case nickname /// 昵称
}

public extension RegexRuleEnum {
    ///
    func regexStaticStr() -> StaticString {
        switch self {
        case .pureNum:
            return #"^[0-9]+$"#
        case .chinese:
            return #"^[\u4e00-\u9fa5]{0,}$"#
        case .letter:
            return #"^[A-Za-z]+$"#
            
        case .moneyNoPoint:
            return #"^[1-9][0-9]*$"#
        case .moneyNoPointNoZeroStart:
            return #"^(0|[1-9][0-9]*)$"#
            
        case .moneyPointCanEnd:
            return #"^[0-9]+.?([0-9]{1,2})?$"#
        case .moneyPointNoEnd:
            return #"^[0-9]+(.[0-9]{1,2})?$"#
        case .moneyStandard:
            return #"^[0-9]+(.[0-9]{2})?$"#
            
        case .phone:
            return #"^1[3-9]\d{9}$"#
        case .url:
            return #"^(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?$"#
        case .email:
            return #"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"#
        case .idCard:
            return #"^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$"#
        
        case .password:
            return #"^[a-zA-Z]\w{5,17}$"#
        case .passwordStrong:
            return #"^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$"#
        case .passwordStrongNoSpecial:
            return #"^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$"#
        
        case .nickname:
            return #"[a-zA-Z\\u4E00-\\u9FA5]{1,20}"#
        }
    }
}

// MARK: - 正则
public extension String {
    
    /// 是否匹配
    func isMatch(_ rule: RegexRuleEnum) -> Bool {
        return Regex(rule.regexStaticStr()).isMatched(by: self)
    }
    
    func firstMatch(_ rule: RegexRuleEnum) -> String {
        return Regex(rule.regexStaticStr()).firstMatch(in: self)?.value ?? ""
    }
    
}

// MARK: - html
public extension String {
    
    /// 富文本转网页  加上header meta 什么的
    /// - Parameters:
    ///   - meta: meta
    ///   - size: fontsize 默认 15px
    ///   - imageWidth: 是否全宽
    /// - Returns:
    func convertToHtmlMeta(meta: Bool = true, mineSize size: Int = 15, imageWidth: Bool = true) -> String {
        let headerStr = "\n <!DOCTYPE html> \n <html> \n <head> \n <meta charset=\"utf-8\"> \n "
        
        let metaStr = "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no\" /> \n "
        
        let adjustFontSizeStr = "<style type=\"text/css\"> \n body {font-size:\(size)px;}\n </style> \n "
        
        let bodyStr = "</head>\n <body>\n "
        
        let adjustImageWidthStr = "<script type='text/javascript'> \nwindow.onload = function(){\n var $img = document.getElementsByTagName('img');\n  for(var p in  $img){\n  $img[p].style.width = '100%';\n  $img[p].style.height ='auto'\n }\n } \n </script> \n"
        
        let footerStr = "\n </body>\n</html>"
        
        return "\(headerStr) \(meta ? metaStr : "") \(size > 0 ? adjustFontSizeStr : "") \(bodyStr) \(imageWidth ? adjustImageWidthStr : "") \(self) \(footerStr)"
    }
    
    /// 去掉前后空格
    func trimmed() -> String {
        return self.trimmingCharacters(in: .decimalDigits)
    }
    
}
